Test Failed
Branch master (1006b0)
by Julien
02:54
created

module.exports   A

Complexity

Conditions 1
Paths 2

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 3
rs 10
c 1
b 0
f 0
cc 1
nc 2
nop 1
1
/*!
2
 * Bootstrap's Gruntfile
3
 * http://getbootstrap.com
4
 * Copyright 2013-2016 Twitter, Inc.
5
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
6
 */
7
8
module.exports = function (grunt) {
9
  'use strict';
10
11
  // Force use of Unix newlines
12
  grunt.util.linefeed = '\n';
13
14
  RegExp.quote = function (string) {
15
    return string.replace(/[-\\^$*+?.()|[\]{}]/g, '\\$&');
16
  };
17
18
  var fs = require('fs');
19
  var path = require('path');
20
  var generateGlyphiconsData = require('./grunt/bs-glyphicons-data-generator.js');
21
  var BsLessdocParser = require('./grunt/bs-lessdoc-parser.js');
22
  var getLessVarsData = function () {
23
    var filePath = path.join(__dirname, 'less/variables.less');
24
    var fileContent = fs.readFileSync(filePath, { encoding: 'utf8' });
25
    var parser = new BsLessdocParser(fileContent);
26
    return { sections: parser.parseFile() };
27
  };
28
  var generateRawFiles = require('./grunt/bs-raw-files-generator.js');
29
  var generateCommonJSModule = require('./grunt/bs-commonjs-generator.js');
30
  var configBridge = grunt.file.readJSON('./grunt/configBridge.json', { encoding: 'utf8' });
31
32
  Object.keys(configBridge.paths).forEach(function (key) {
33
    configBridge.paths[key].forEach(function (val, i, arr) {
34
      arr[i] = path.join('./docs/assets', val);
35
    });
36
  });
37
38
  // Project configuration.
39
  grunt.initConfig({
40
41
    // Metadata.
42
    pkg: grunt.file.readJSON('package.json'),
43
    banner: '/*!\n' +
44
            ' * Bootstrap v<%= pkg.version %> (<%= pkg.homepage %>)\n' +
45
            ' * Copyright 2011-<%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' +
46
            ' * Licensed under the <%= pkg.license %> license\n' +
47
            ' */\n',
48
    jqueryCheck: configBridge.config.jqueryCheck.join('\n'),
49
    jqueryVersionCheck: configBridge.config.jqueryVersionCheck.join('\n'),
50
51
    // Task configuration.
52
    clean: {
53
      dist: 'dist',
54
      docs: 'docs/dist'
55
    },
56
57
    jshint: {
58
      options: {
59
        jshintrc: 'js/.jshintrc'
60
      },
61
      grunt: {
62
        options: {
63
          jshintrc: 'grunt/.jshintrc'
64
        },
65
        src: ['Gruntfile.js', 'package.js', 'grunt/*.js']
66
      },
67
      core: {
68
        src: 'js/*.js'
69
      },
70
      test: {
71
        options: {
72
          jshintrc: 'js/tests/unit/.jshintrc'
73
        },
74
        src: 'js/tests/unit/*.js'
75
      },
76
      assets: {
77
        src: ['docs/assets/js/src/*.js', 'docs/assets/js/*.js', '!docs/assets/js/*.min.js']
78
      }
79
    },
80
81
    jscs: {
82
      options: {
83
        config: 'js/.jscsrc'
84
      },
85
      grunt: {
86
        src: '<%= jshint.grunt.src %>'
87
      },
88
      core: {
89
        src: '<%= jshint.core.src %>'
90
      },
91
      test: {
92
        src: '<%= jshint.test.src %>'
93
      },
94
      assets: {
95
        options: {
96
          requireCamelCaseOrUpperCaseIdentifiers: null
97
        },
98
        src: '<%= jshint.assets.src %>'
99
      }
100
    },
101
102
    concat: {
103
      options: {
104
        banner: '<%= banner %>\n<%= jqueryCheck %>\n<%= jqueryVersionCheck %>',
105
        stripBanners: false
106
      },
107
      bootstrap: {
108
        src: [
109
          'js/transition.js',
110
          'js/alert.js',
111
          'js/button.js',
112
          'js/carousel.js',
113
          'js/collapse.js',
114
          'js/dropdown.js',
115
          'js/modal.js',
116
          'js/tooltip.js',
117
          'js/popover.js',
118
          'js/scrollspy.js',
119
          'js/tab.js',
120
          'js/affix.js'
121
        ],
122
        dest: 'dist/js/<%= pkg.name %>.js'
123
      }
124
    },
125
126
    uglify: {
127
      options: {
128
        compress: {
129
          warnings: false
130
        },
131
        mangle: true,
132
        preserveComments: /^!|@preserve|@license|@cc_on/i
133
      },
134
      core: {
135
        src: '<%= concat.bootstrap.dest %>',
136
        dest: 'dist/js/<%= pkg.name %>.min.js'
137
      },
138
      customize: {
139
        src: configBridge.paths.customizerJs,
140
        dest: 'docs/assets/js/customize.min.js'
141
      },
142
      docsJs: {
143
        src: configBridge.paths.docsJs,
144
        dest: 'docs/assets/js/docs.min.js'
145
      }
146
    },
147
148
    qunit: {
149
      options: {
150
        inject: 'js/tests/unit/phantom.js'
151
      },
152
      files: 'js/tests/index.html'
153
    },
154
155
    less: {
156
      compileCore: {
157
        options: {
158
          strictMath: true,
159
          sourceMap: true,
160
          outputSourceFiles: true,
161
          sourceMapURL: '<%= pkg.name %>.css.map',
162
          sourceMapFilename: 'dist/css/<%= pkg.name %>.css.map'
163
        },
164
        src: 'less/bootstrap.less',
165
        dest: 'dist/css/<%= pkg.name %>.css'
166
      },
167
      compileTheme: {
168
        options: {
169
          strictMath: true,
170
          sourceMap: true,
171
          outputSourceFiles: true,
172
          sourceMapURL: '<%= pkg.name %>-theme.css.map',
173
          sourceMapFilename: 'dist/css/<%= pkg.name %>-theme.css.map'
174
        },
175
        src: 'less/theme.less',
176
        dest: 'dist/css/<%= pkg.name %>-theme.css'
177
      }
178
    },
179
180
    autoprefixer: {
181
      options: {
182
        browsers: configBridge.config.autoprefixerBrowsers
183
      },
184
      core: {
185
        options: {
186
          map: true
187
        },
188
        src: 'dist/css/<%= pkg.name %>.css'
189
      },
190
      theme: {
191
        options: {
192
          map: true
193
        },
194
        src: 'dist/css/<%= pkg.name %>-theme.css'
195
      },
196
      docs: {
197
        src: ['docs/assets/css/src/docs.css']
198
      },
199
      examples: {
200
        expand: true,
201
        cwd: 'docs/examples/',
202
        src: ['**/*.css'],
203
        dest: 'docs/examples/'
204
      }
205
    },
206
207
    csslint: {
208
      options: {
209
        csslintrc: 'less/.csslintrc'
210
      },
211
      dist: [
212
        'dist/css/bootstrap.css',
213
        'dist/css/bootstrap-theme.css'
214
      ],
215
      examples: [
216
        'docs/examples/**/*.css'
217
      ],
218
      docs: {
219
        options: {
220
          ids: false,
221
          'overqualified-elements': false
222
        },
223
        src: 'docs/assets/css/src/docs.css'
224
      }
225
    },
226
227
    cssmin: {
228
      options: {
229
        // TODO: disable `zeroUnits` optimization once clean-css 3.2 is released
230
        //    and then simplify the fix for https://github.com/twbs/bootstrap/issues/14837 accordingly
231
        compatibility: 'ie8',
232
        keepSpecialComments: '*',
233
        sourceMap: true,
234
        sourceMapInlineSources: true,
235
        advanced: false
236
      },
237
      minifyCore: {
238
        src: 'dist/css/<%= pkg.name %>.css',
239
        dest: 'dist/css/<%= pkg.name %>.min.css'
240
      },
241
      minifyTheme: {
242
        src: 'dist/css/<%= pkg.name %>-theme.css',
243
        dest: 'dist/css/<%= pkg.name %>-theme.min.css'
244
      },
245
      docs: {
246
        src: [
247
          'docs/assets/css/ie10-viewport-bug-workaround.css',
248
          'docs/assets/css/src/pygments-manni.css',
249
          'docs/assets/css/src/docs.css'
250
        ],
251
        dest: 'docs/assets/css/docs.min.css'
252
      }
253
    },
254
255
    csscomb: {
256
      options: {
257
        config: 'less/.csscomb.json'
258
      },
259
      dist: {
260
        expand: true,
261
        cwd: 'dist/css/',
262
        src: ['*.css', '!*.min.css'],
263
        dest: 'dist/css/'
264
      },
265
      examples: {
266
        expand: true,
267
        cwd: 'docs/examples/',
268
        src: '**/*.css',
269
        dest: 'docs/examples/'
270
      },
271
      docs: {
272
        src: 'docs/assets/css/src/docs.css',
273
        dest: 'docs/assets/css/src/docs.css'
274
      }
275
    },
276
277
    copy: {
278
      fonts: {
279
        expand: true,
280
        src: 'fonts/**',
281
        dest: 'dist/'
282
      },
283
      docs: {
284
        expand: true,
285
        cwd: 'dist/',
286
        src: [
287
          '**/*'
288
        ],
289
        dest: 'docs/dist/'
290
      }
291
    },
292
293
    connect: {
294
      server: {
295
        options: {
296
          port: 3000,
297
          base: '.'
298
        }
299
      }
300
    },
301
302
    jekyll: {
303
      options: {
304
        bundleExec: true,
305
        config: '_config.yml',
306
        incremental: false
307
      },
308
      docs: {},
309
      github: {
310
        options: {
311
          raw: 'github: true'
312
        }
313
      }
314
    },
315
316
    htmlmin: {
317
      dist: {
318
        options: {
319
          collapseBooleanAttributes: true,
320
          collapseWhitespace: true,
321
          conservativeCollapse: true,
322
          decodeEntities: false,
323
          minifyCSS: {
324
            compatibility: 'ie8',
325
            keepSpecialComments: 0
326
          },
327
          minifyJS: true,
328
          minifyURLs: false,
329
          processConditionalComments: true,
330
          removeAttributeQuotes: true,
331
          removeComments: true,
332
          removeOptionalAttributes: true,
333
          removeOptionalTags: true,
334
          removeRedundantAttributes: true,
335
          removeScriptTypeAttributes: true,
336
          removeStyleLinkTypeAttributes: true,
337
          removeTagWhitespace: false,
338
          sortAttributes: true,
339
          sortClassName: true
340
        },
341
        expand: true,
342
        cwd: '_gh_pages',
343
        dest: '_gh_pages',
344
        src: [
345
          '**/*.html',
346
          '!examples/**/*.html'
347
        ]
348
      }
349
    },
350
351
    pug: {
352
      options: {
353
        pretty: true,
354
        data: getLessVarsData
355
      },
356
      customizerVars: {
357
        src: 'docs/_pug/customizer-variables.pug',
358
        dest: 'docs/_includes/customizer-variables.html'
359
      },
360
      customizerNav: {
361
        src: 'docs/_pug/customizer-nav.pug',
362
        dest: 'docs/_includes/nav/customize.html'
363
      }
364
    },
365
366
    htmllint: {
367
      options: {
368
        ignore: [
369
          'Attribute "autocomplete" not allowed on element "button" at this point.',
370
          'Attribute "autocomplete" is only allowed when the input type is "color", "date", "datetime", "datetime-local", "email", "hidden", "month", "number", "password", "range", "search", "tel", "text", "time", "url", or "week".',
371
          'Element "img" is missing required attribute "src".'
372
        ]
373
      },
374
      src: '_gh_pages/**/*.html'
375
    },
376
377
    watch: {
378
      src: {
379
        files: '<%= jshint.core.src %>',
380
        tasks: ['jshint:core', 'qunit', 'concat']
381
      },
382
      test: {
383
        files: '<%= jshint.test.src %>',
384
        tasks: ['jshint:test', 'qunit']
385
      },
386
      less: {
387
        files: 'less/**/*.less',
388
        tasks: 'less'
389
      }
390
    },
391
392
    'saucelabs-qunit': {
393
      all: {
394
        options: {
395
          build: process.env.TRAVIS_JOB_ID,
396
          throttled: 10,
397
          maxRetries: 3,
398
          maxPollRetries: 4,
399
          urls: ['http://127.0.0.1:3000/js/tests/index.html?hidepassed'],
400
          browsers: grunt.file.readYAML('grunt/sauce_browsers.yml')
401
        }
402
      }
403
    },
404
405
    exec: {
406
      npmUpdate: {
407
        command: 'npm update'
408
      }
409
    },
410
411
    compress: {
412
      main: {
413
        options: {
414
          archive: 'bootstrap-<%= pkg.version %>-dist.zip',
415
          mode: 'zip',
416
          level: 9,
417
          pretty: true
418
        },
419
        files: [
420
          {
421
            expand: true,
422
            cwd: 'dist/',
423
            src: ['**'],
424
            dest: 'bootstrap-<%= pkg.version %>-dist'
425
          }
426
        ]
427
      }
428
    }
429
430
  });
431
432
433
  // These plugins provide necessary tasks.
434
  require('load-grunt-tasks')(grunt, { scope: 'devDependencies' });
435
  require('time-grunt')(grunt);
436
437
  // Docs HTML validation task
438
  grunt.registerTask('validate-html', ['jekyll:docs', 'htmllint']);
439
440
  var runSubset = function (subset) {
441
    return !process.env.TWBS_TEST || process.env.TWBS_TEST === subset;
442
  };
443
  var isUndefOrNonZero = function (val) {
444
    return val === undefined || val !== '0';
445
  };
446
447
  // Test task.
448
  var testSubtasks = [];
449
  // Skip core tests if running a different subset of the test suite
450
  if (runSubset('core') &&
451
      // Skip core tests if this is a Savage build
452
      process.env.TRAVIS_REPO_SLUG !== 'twbs-savage/bootstrap') {
453
    testSubtasks = testSubtasks.concat(['dist-css', 'dist-js', 'csslint:dist', 'test-js', 'docs']);
454
  }
455
  // Skip HTML validation if running a different subset of the test suite
456
  if (runSubset('validate-html') &&
457
      // Skip HTML5 validator on Travis when [skip validator] is in the commit message
458
      isUndefOrNonZero(process.env.TWBS_DO_VALIDATOR)) {
459
    testSubtasks.push('validate-html');
460
  }
461
  // Only run Sauce Labs tests if there's a Sauce access key
462
  if (typeof process.env.SAUCE_ACCESS_KEY !== 'undefined' &&
463
      // Skip Sauce if running a different subset of the test suite
464
      runSubset('sauce-js-unit') &&
465
      // Skip Sauce on Travis when [skip sauce] is in the commit message
466
      isUndefOrNonZero(process.env.TWBS_DO_SAUCE)) {
467
    testSubtasks.push('connect');
468
    testSubtasks.push('saucelabs-qunit');
469
  }
470
  grunt.registerTask('test', testSubtasks);
471
  grunt.registerTask('test-js', ['jshint:core', 'jshint:test', 'jshint:grunt', 'jscs:core', 'jscs:test', 'jscs:grunt', 'qunit']);
472
473
  // JS distribution task.
474
  grunt.registerTask('dist-js', ['concat', 'uglify:core', 'commonjs']);
475
476
  // CSS distribution task.
477
  grunt.registerTask('less-compile', ['less:compileCore', 'less:compileTheme']);
478
  grunt.registerTask('dist-css', ['less-compile', 'autoprefixer:core', 'autoprefixer:theme', 'csscomb:dist', 'cssmin:minifyCore', 'cssmin:minifyTheme']);
479
480
  // Full distribution task.
481
  grunt.registerTask('dist', ['clean:dist', 'dist-css', 'copy:fonts', 'dist-js']);
482
483
  // Default task.
484
  grunt.registerTask('default', ['clean:dist', 'copy:fonts', 'test']);
485
486
  grunt.registerTask('build-glyphicons-data', function () { generateGlyphiconsData.call(this, grunt); });
487
488
  // task for building customizer
489
  grunt.registerTask('build-customizer', ['build-customizer-html', 'build-raw-files']);
490
  grunt.registerTask('build-customizer-html', 'pug');
491
  grunt.registerTask('build-raw-files', 'Add scripts/less files to customizer.', function () {
492
    var banner = grunt.template.process('<%= banner %>');
493
    generateRawFiles(grunt, banner);
494
  });
495
496
  grunt.registerTask('commonjs', 'Generate CommonJS entrypoint module in dist dir.', function () {
497
    var srcFiles = grunt.config.get('concat.bootstrap.src');
498
    var destFilepath = 'dist/js/npm.js';
499
    generateCommonJSModule(grunt, srcFiles, destFilepath);
500
  });
501
502
  // Docs task.
503
  grunt.registerTask('docs-css', ['autoprefixer:docs', 'autoprefixer:examples', 'csscomb:docs', 'csscomb:examples', 'cssmin:docs']);
504
  grunt.registerTask('lint-docs-css', ['csslint:docs', 'csslint:examples']);
505
  grunt.registerTask('docs-js', ['uglify:docsJs', 'uglify:customize']);
506
  grunt.registerTask('lint-docs-js', ['jshint:assets', 'jscs:assets']);
507
  grunt.registerTask('docs', ['docs-css', 'lint-docs-css', 'docs-js', 'lint-docs-js', 'clean:docs', 'copy:docs', 'build-glyphicons-data', 'build-customizer']);
508
  grunt.registerTask('docs-github', ['jekyll:github', 'htmlmin']);
509
510
  grunt.registerTask('prep-release', ['dist', 'docs', 'docs-github', 'compress']);
511
};
512